package com.xr.blog.aop;

import com.alibaba.fastjson.JSONObject;

import com.xr.blog.exception.CustomException;
import com.xr.blog.exception.UserPasswordNotMatchException;
import com.xr.blog.tools.constant.Code;
import com.xr.blog.tools.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * description : 全局异常处理器
 *
 * @author 幸仁杰
 * @create 2020/6/24 15:47
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(com.xr.blog.aop.GlobalExceptionHandler.class);

    /**
     * 方法入参支持：Exception、SessionAttribute、@RequestAttribute、HttpServletRequest、HttpServletResponse、HttpSession
     * 方法返回支持: ModelAndView、@ResponseBody、ResponseEntity
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public void error(HttpServletResponse response, Exception e) {
        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        LOGGER.error("全局异常捕获", e);
        try {
            response.getWriter().print(JSONObject.toJSONString(Result.of(Code.SC_INTERNAL_SERVER_ERROR.getState(), Code.SC_INTERNAL_SERVER_ERROR.getDescription(), e.toString())));
        } catch (IOException exc) {
            LOGGER.error("全局异常捕获响应失败", exc);
        }
    }

    /**
     * 用于捕获接口方法入参时，数据校验不通过抛出的异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    //@ResponseStatus(HttpStatus.BAD_REQUEST)  加上此注解后，该异常处理器返回给客户端的状态码将是HttpStatus.BAD_REQUEST，而我需要客户端拦截到此处理器内部返回的状态码，并提示返回的信息
    public void handleMethodArgumentNotValid(HttpServletResponse response, MethodArgumentNotValidException e) {
        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        BindingResult bindingResult = e.getBindingResult();
        Map<String, Object> map = new HashMap<>();
        for (FieldError error : bindingResult.getFieldErrors()) {
            String field = error.getField();
            String msg = error.getDefaultMessage();
            map.put(field, msg);
        }
        try {
            response.getWriter().print(JSONObject.toJSONString(Result.of(Code.SC_PRECONDITION_FAILED.getState(), Code.SC_PRECONDITION_FAILED.getDescription(), map)));
        } catch (IOException exc) {
            LOGGER.error("统一参数异常处理响应失败", exc);
        }
    }

    /**
     * 用于捕获自定义的UserPasswordNotMatchException异常（用户名和密码不通过时抛出的异常）
     */
    @ExceptionHandler(UserPasswordNotMatchException.class)
    public void HandlerUserPasswordNotMatchException(HttpServletResponse response, UserPasswordNotMatchException e) {
        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        try {
            response.getWriter().print(JSONObject.toJSONString(Result.of(Code.VAILDATE_ERROR.getState(), e.getMessage(), e.getMessage())));
        } catch (IOException exc) {
            LOGGER.error("用户名密码异常捕获响应失败", exc);
        }
    }

    /**
     * 用于捕获自定义的CustomException异常
     */
    @ExceptionHandler(CustomException.class)
    public void HandlerCustomException(HttpServletResponse response, CustomException e) {
        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        try {
            response.getWriter().print(JSONObject.toJSONString(Result.of(Code.VAILDATE_ERROR.getState(), e.getMessage(), e.getMessage())));
        } catch (IOException exc) {
            LOGGER.error("异常捕获响应失败", exc);
        }
    }
}
